package com.fujin.gulimall.gulimall.auth.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.fujin.common.Vo.SocialUser;
import com.fujin.common.constant.SmsConstant;
import com.fujin.common.exception.BizCodeEnume;
import com.fujin.common.utils.HttpUtils;
import com.fujin.common.utils.R;
import com.fujin.gulimall.gulimall.auth.Vo.MemberRsepVo;
import com.fujin.gulimall.gulimall.auth.Vo.UserLoginVo;
import com.fujin.gulimall.gulimall.auth.Vo.UserRegisterVo;
import com.fujin.gulimall.gulimall.auth.feign.MemBerFeign;
import com.fujin.gulimall.gulimall.auth.feign.ThirdPartyFeign;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.net.BindException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @title: LoginController
 * @Author uIn
 * @Date: 2022/2/25 9:38
 * @Version 1.0
 */
@Controller
public class LoginController {

    @Autowired
    private ThirdPartyFeign thirdPartyFeign;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MemBerFeign memBerFeign;

    /**
     * 发送短信验证码
     * @param phone
     * @return
     */
    @ResponseBody
    @PostMapping("/sms/sendCode")
    public R SendSms(@RequestParam("phone") String phone){
        //TODO 防止接口恶意刷新

        //防止刷新页面引起可以一直发送验证码,设置一分钟只能发送一次
        String redisCode = redisTemplate.opsForValue().get(SmsConstant.SMS_CODE_CACHE_PREFIX + phone);
        if (!StringUtils.isEmpty(redisCode)){
            String[] split = redisCode.split("_");
            long l = Long.parseLong(split[1]);
            //当前时间减去存入验证码的时间，如果小于60秒，就得等60后才能再发
            if (System.currentTimeMillis() - l < 60000){
                return R.error(BizCodeEnume.SMS_CODE_EXCEPTION.getCode(),BizCodeEnume.SMS_CODE_EXCEPTION.getMsg());
            }
        }

        //生成随机验证码
        String code = UUID.randomUUID().toString().substring(0,5);
        //验证码加上时间为了防止一直刷新页面重复发送短信
        String redis_code = code+"_"+System.currentTimeMillis();

        //将验证码存入redis、并设置过去时间为15分钟
        //key存储时间号码(sms:code:137947xxxx) value存储验证码+当前时间戳
        //用于后续校验验证码填写是否正确
        redisTemplate.opsForValue().set(SmsConstant.SMS_CODE_CACHE_PREFIX+phone,redis_code,15, TimeUnit.MINUTES);

        thirdPartyFeign.sendCode(phone,code);

        return R.ok();
    }

    /**
     * 注册
     * @param userRegisterVo：前端传递数据
     * @param bindingResult：获取JSR303出现的错误
     * @param attributes：重定向后的数据无法通过Model获取，RedirectAttributes可以得到
     * @return
     */
    @PostMapping("/regist")
    public String register(@Valid UserRegisterVo userRegisterVo,
                           BindingResult bindingResult,
                           RedirectAttributes attributes){

        //1.判断校验是否通过
        Map<String, String> errors = new HashMap<>();
        if (bindingResult.hasErrors()){
            //1.1 如果校验不通过，则封装校验结果
            bindingResult.getFieldErrors().forEach(item->{
                // 获取错误的属性名和错误信息
                errors.put(item.getField(), item.getDefaultMessage());
                //1.2 将错误信息封装到session中
                attributes.addFlashAttribute("errors", errors);
            });

            //1.2 重定向到注册页
            //这里不能使用转发，使用转发会出现"Request method POST not supported"错误
            //因为转发是通过get请求，而我们注册是使用post请求
            return "redirect:http://localhost:20000/reg.html";
        }else {
            //2、数据校验通过

            //2.2、判断验证是否正确,存的时候key为:SmsConstant.SMS_CODE_CACHE_PREFIX + phone
            String s = redisTemplate.opsForValue().get(SmsConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getPhone());
            if (!StringUtils.isEmpty(s)){
                //value为:验证码_时间
                String[] split = s.split("_");
                if (userRegisterVo.getCode().equals(split[0])){
                    //删除redis缓存验证码数据
                    redisTemplate.delete(SmsConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getCode());
                    //验证码正确，调用远程会员服务进行保存
                    R r = memBerFeign.regist(userRegisterVo);
                    if (r.getCode() == 0){
                        //调用成功，跳转登录页面
                        return "redirect:http://localhost:20000/login.html";
                    }else{
                        //远程调用失败
                        //调用失败，返回注册页并显示错误信息
                        String msg = (String) r.get("msg");
                        errors.put("msg", msg);
                        attributes.addFlashAttribute("errors", errors);
                        return "redirect:http://auth.gulimall.com/reg.html";
                    }
                }else {
                    //验证码错误
                    //查询为空说明此时验证码已经失效
                    errors.put("code","验证码有误，请重试");
                    attributes.addFlashAttribute("errors", errors);
                    return "redirect:http://localhost:20000/reg.html";
                }
            }else {
                //查询为空说明此时验证码已经失效
                errors.put("code","验证码已失效，请重试");
                attributes.addFlashAttribute("errors", errors);
                return "redirect:http://localhost:20000/reg.html";
            }
        }
    }

    /**
     * 登录
     * @param userLoginVo
     * @return
     */
    @PostMapping("/login")
    public String login(UserLoginVo userLoginVo,RedirectAttributes attributes){
        //调用远程会员服务 进行登录
        R login = memBerFeign.login(userLoginVo);
        if (login.getCode() == 0){
            //调用成功，说明登录成功直接跳转 商城首页
            return "redirect:http://localhost:10000";
        }else {
            //登录失败，返回登录页面
            String msg = (String) login.get("msg");
            Map<String, String> errors = new HashMap<>();
            errors.put("msg", msg);
            attributes.addFlashAttribute("errors", errors);
            return "redirect:http://localhost:20000/login.html";
        }
    }

    /**
     * 社交微博登录
     * @param code
     * @param session
     * @return
     */
    @GetMapping("/auth2.0/success")
    public String authLogin(@RequestParam("code") String code, HttpSession session){
        // 根据code换取 Access Token
        Map<String,String> map = new HashMap<>();
        map.put("client_id", "1050694533");
        map.put("client_secret", "57fc66954aa79334bb831471b2d96d5b");
        map.put("grant_type", "authorization_code");
        map.put("redirect_uri", "http://localhost:20000/auth2.0/success");
        map.put("code", code);

        Map<String, String> headers = new HashMap<>();
        try {
            HttpResponse response = HttpUtils.doPost("https://api.weibo.com", "/oauth2/access_token", "post", headers, null, map);
            if (response.getStatusLine().getStatusCode() == 200){
                //获取响应体 返回的code
                String json = EntityUtils.toString(response.getEntity());
                //封装得到微博接口返回信息
                SocialUser socialUser = JSON.parseObject(json, SocialUser.class);

                //远程调用会员服务
                //通过token调用微博接口获取相关信息(用户信息、微博内容、评论)
                R r = memBerFeign.login(socialUser);
                if (r.getCode() == 0){
                    //调用成功
                    MemberRsepVo memberEntity = r.getData("memberEntity", new TypeReference<MemberRsepVo>() {
                    });
                    System.out.println("登录成功:"+memberEntity);
                    // 第一次使用session 命令浏览器保存这个用户信息 JESSIONSEID 每次只要访问这个网站就会带上这个cookie
                    // 在发卡的时候扩大session作用域 (指定域名为父域名)
                    // TODO 1.默认发的当前域的session (需要解决子域session共享问题)
                    // TODO 2.使用JSON的方式序列化到redis
                    session.setAttribute("loginUser",memberEntity);

                    //登录成功
                    return "redirect:http://localhost:10000";
                }else {
                    return "redirect:http://localhost:20000/login.html";
                }

            }else {
                return "redirect:http://localhost:20000/login.html";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "redirect:http://localhost:20000/login.html";
    }

}
